#ifndef ___fat32_transaccionB2_leer_archivo

#define ___fat32_transaccionB2_leer_archivo 1

#include "f32_mto.c"

#include "f32_st01.c"
#include "f32_st02.c"
#include "f32_st18.c"

enum fat32trB2_errores {
  FAT32_B2_DESCRIPTOR_NO_VALIDO = 1,
  FAT32_B2_ARCHIVO_NO_EXISTE = 2,
  FAT32_B2_ES_DIRECTORIO = 3,
  FAT32_B2_POSICION_LECTURA_SUPERA_FIN_ARCHIVO = 4,
  FAT32_B2_NO_PERMITIDO = 5
};

struct fat32trB2_datos_entrada {
  unsigned int remitente;
  unsigned long long descriptor;
  unsigned long inicio;
  unsigned long cantidad;
};

struct fat32trB2_datos_internos {
  unsigned int remitenteMensaje,
  unsigned long long descriptor;
  unsigned long posicionInicio;
  unsigned long cantidadDatos;
  fat32_apertura_archivo datosApertura;
  signed short errorDevuelto;
  unsigned char finArchivo;
  void * datosInternos;
  char * datosArchivo;
  unsigned int conexion;
};

void fat32tr_leer_archivo(unsigned int, unsigned long long, unsigned long, unsigned long);
int fat32ctr_leer_archivo(FAT32_PARAMS_CREACION_TRANSACCION);
int fat32etr_leer_archivo(FAT32_PARAMS_TRANSACCION);

void fat32tr_leer_archivo (unsigned int remitente, unsigned long long descriptor, unsigned long posicionInicial, unsigned long cantidad) {
  struct fat32trB2_datos_entrada datos;
  datos.remitente = remitente;
  datos.descriptor = descriptor;
  datos.inicio = posicionInicial;
  datos.cantidad = cantidad;
  fat32_crear_transaccion(&fat32ctr_leer_archivo, &datos, sizeof datos);
}

int fat32ctr_leer_archivo (FAT32_PARAMS_CREACION_TRANSACCION) {
  struct fat32trB2_datos_entrada * de = datosIniciales;
  struct fat32trB2_datos_internos * di = malloc(sizeof(struct fat32trB2_datos_internos));
  di -> remitenteMensaje = de -> remitente;
  di -> descriptor = de -> descriptor;
  di -> posicionInicial = de -> inicio;
  di -> cantidadDatos = de -> cantidad;
  *datos = di;
  *handler = &fat32etr_leer_archivo;
  return 0xE100;
}

int fat32etr_leer_archivo (FAT32_PARAMS_TRANSACCION) {
  unsigned char estado1;
  int estado2;
  estado2 = estado >> 8;
  estado1 = estado & 255;
  struct fat32trB2_datos_internos * datosT = *datos;
  switch (estado2) {
  case 0x01:
    estado1 = fat32st_obtener_conexion(estado1, numeroTransaccion, &(datosT -> conexion), resultadoOperacion, datosOperacion);
    if (!estado1) estado2 = 0x02;
    break;
  case 0x02:
    estado1 = fat32st_leer_datos_de_archivo(estado1, numeroTransaccion, (datosT -> datosApertura).clusterInicial, datosT -> posicionInicio,
                                                   datosT -> cantidadDatos, &(datosT -> datosInternos), resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> datosArchivo = datosT -> datosInternos;
      estado2 = 0xE1;
      estado1 = 2;
    }
    break;
  case 0x03:
    estado1 = fat32st_liberar_conexion(estado1, numeroTransaccion);
    if (!estado1) {
      estado2 = 0xE1;
      estado1 = 3;
    }
    break;
  case 0xE1:
    switch (estado1) {
    case 0:
      datosT -> datosApertura = fat32_obtener_apertura(datosT -> descriptor);
      if (!(datosT -> datosApertura).descriptor) {
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_NO_LEYO_ARCHIVO, datosT -> descriptor,
                                                                                            (int) FAT32_B2_NO_PERMITIDO);
        free(datosT);
        estado1 = 0;
        estado2 = 0;
      } else {
        datosT -> errorDevuelto = -1;
        estado1 = 1;
      }
      break;
    case 1:
      if ((datosT -> datosApertura).tipo == 1) {
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_NO_LEYO_ARCHIVO, datosT -> descriptor,
                                                                                            (int) FAT32_B2_NO_PERMITIDO);
        free(datosT);
        estado1 = 0;
        estado2 = 0;
      } else if ((datosT -> posicionInicio) >= ((datosT -> datosApertura).tamano)) {
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_NO_LEYO_ARCHIVO, datosT -> descriptor,
                                                                     (int) FAT32_B2_POSICION_LECTURA_SUPERA_FIN_ARCHIVO);
        free(datosT);
        estado1 = 0;
        estado2 = 0;
      } else {
        if (((datosT -> posicionInicio) + (datosT -> cantidadDatos)) >= ((datosT -> datosApertura).tamano)) {
          datosT -> finArchivo = 1;
          datosT -> cantidadDatos = ((datosT -> datosApertura).tamano) - (datosT -> posicionInicio);
        } else
          datosT -> finArchivo = 0;
        estado1 = 0;
        estado2 = 0x01;
      }
      break;
    case 2:
      mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_INICIO_DATOS_ARCHIVO, datosT -> descriptor, 
                                                                      (long) (((datosT -> cantidadDatos) + 16383) / 16384));
      unsigned long posicionActual = 0;
      unsigned long restoDatos = datosT -> cantidadDatos;
      unsigned long parteActual = 0;
      unsigned short datosActuales;
      envio:
      parteActual ++;
      datosActuales = (restoDatos > 16384) ? 16384 : restoDatos;
      mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_DATOS_ARCHIVO, datosT -> descriptor, parteActual,
                                                       (int) datosActuales, (void *) ((datosT -> datosArchivo) + posicionActual));
      posicionActual += datosActuales;
      restoDatos -= datosActuales;
      if (restoDatos) goto envio;
      mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_FIN_DATOS_ARCHIVO, datosT -> descriptor,
                                                                                           (int) (datosT -> finArchivo));
      estado2 = 0x03;
      estado1 = 0;
      break;
    case 3:
      free(datosT -> datosArchivo);
      free(datosT);
      estado1 = 0;
      estado2 = 0;
    }
    break;
  }
  return (estado2 << 8) | estado1;
}

#endif